﻿using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json;
using System;
using XUCore.Ddd.Domain;
using XUCore.Serializer;

namespace XUCore.NetCore.RestFul
{
    public static class FormatterMvcBuilderExtensions
    {
        //internal static IMvcBuilder AddFormatters(this IMvcBuilder builder)
        //{
        //    if (builder == null)
        //        throw new ArgumentNullException(nameof(builder));

        //    return AddFormatters(builder, ApiFormatterOptionsConfiguration: null);
        //}

        //internal static IMvcCoreBuilder AddFormatters(this IMvcCoreBuilder builder)
        //{
        //    if (builder == null)
        //        throw new ArgumentNullException(nameof(builder));

        //    return AddFormatters(builder, ApiFormatterOptionsConfiguration: null);
        //}
        /// <summary>
        /// 注册restful风格api输出
        /// </summary>
        /// <remarks>
        ///     如果需要messagepack格式的输出（默认大写，于前端来决定大小写输出）  在接口处可以增加标签来限定入口格式 ： [MessagePackResponseContentType]
        ///     客户端接入指南：
        ///     https://github.com/xuyiazl/XUCore.NetCore/tree/net6/src/XUCore.NetCore/Formatter
        /// </remarks>
        /// <param name="builder"></param>
        /// <param name="apiFormatterOptionsConfiguration"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IMvcBuilder AddRestFulFormatters(this IMvcBuilder builder, Action<FormatterOptions> apiFormatterOptionsConfiguration = null)
        {
            return AddFormatters(builder, ApiFormatterOptionsConfiguration: apiFormatterOptionsConfiguration);
        }
        /// <summary>
        /// 注册restful风格api输出
        /// </summary>
        /// <remarks>
        ///     如果需要messagepack格式的输出（默认大写，于前端来决定大小写输出）  在接口处可以增加标签来限定入口格式 ： [MessagePackResponseContentType]
        ///     客户端接入指南：
        ///     https://github.com/xuyiazl/XUCore.NetCore/tree/net6/src/XUCore.NetCore/Formatter
        /// </remarks>
        /// <param name="builder"></param>
        /// <param name="apiFormatterOptionsConfiguration"></param>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException"></exception>
        public static IMvcCoreBuilder AddRestFulFormatters(this IMvcCoreBuilder builder, Action<FormatterOptions> apiFormatterOptionsConfiguration = null)
        {
            return AddFormatters(builder, ApiFormatterOptionsConfiguration: apiFormatterOptionsConfiguration);
        }

        internal static IMvcBuilder AddFormatters(this IMvcBuilder builder, Action<FormatterOptions> ApiFormatterOptionsConfiguration)
        {
            if (builder == null)
                throw new ArgumentNullException(nameof(builder));

            var ApiFormatterOptions = new FormatterOptions();

            ApiFormatterOptions.JsonSerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            ApiFormatterOptions.JsonSerializerSettings.ContractResolver = new LimitPropsContractResolver();
            ApiFormatterOptions.ResolverDefault = ResolverMode.Default;
            ApiFormatterOptions.FormatterResolver = MessagePackSerializerResolver.UnixDateTimeFormatter;
            ApiFormatterOptions.Options = MessagePackSerializerResolver.UnixDateTimeOptions;

            ApiFormatterOptionsConfiguration?.Invoke(ApiFormatterOptions);

            ApiFormatterOptions.Options.WithResolver(ApiFormatterOptions.FormatterResolver);

            foreach (var extension in ApiFormatterOptions.SupportedExtensions)
            {
                foreach (var contentType in ApiFormatterOptions.SupportedResponseFormatters.Keys)
                {
                    builder.AddFormatterMappings(m => m.SetMediaTypeMappingForFormat(extension, new MediaTypeHeaderValue(contentType)));
                }
            }

            //builder.AddMvcOptions(options => options.InputFormatters.Add(new ApiInputFormatter(ApiFormatterOptions)));
            //builder.AddMvcOptions(options => options.OutputFormatters.Add(new ApiOutputFormatter(ApiFormatterOptions)));

            builder.AddMvcOptions(options =>
            {
                options.InputFormatters.Clear();
                options.InputFormatters.Add(new InputFormatter(ApiFormatterOptions));

                options.OutputFormatters.Clear();
                options.OutputFormatters.Add(new OutputFormatter(ApiFormatterOptions));

                if (ApiFormatterOptions.CommandValidationActionFilter)
                    options.Filters.Add<RequestCommandValidationActionFilter>();

                options.Filters.Add<RestFulFormatterFilter>();
            });

            return builder;
        }

        internal static IMvcCoreBuilder AddFormatters(this IMvcCoreBuilder builder, Action<FormatterOptions> ApiFormatterOptionsConfiguration)
        {
            if (builder == null)
                throw new ArgumentNullException(nameof(builder));

            var ApiFormatterOptions = new FormatterOptions();

            ApiFormatterOptions.JsonSerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
            ApiFormatterOptions.JsonSerializerSettings.ContractResolver = new LimitPropsContractResolver();
            ApiFormatterOptions.ResolverDefault = ResolverMode.Default;
            ApiFormatterOptions.FormatterResolver = MessagePackSerializerResolver.UnixDateTimeFormatter;
            ApiFormatterOptions.Options = MessagePackSerializerResolver.UnixDateTimeOptions;

            ApiFormatterOptionsConfiguration?.Invoke(ApiFormatterOptions);

            ApiFormatterOptions.Options.WithResolver(ApiFormatterOptions.FormatterResolver);

            foreach (var extension in ApiFormatterOptions.SupportedExtensions)
            {
                foreach (var contentType in ApiFormatterOptions.SupportedResponseFormatters.Keys)
                {
                    builder.AddFormatterMappings(m => m.SetMediaTypeMappingForFormat(extension, new MediaTypeHeaderValue(contentType)));
                }
            }

            //builder.AddMvcOptions(options => options.InputFormatters.Add(new ApiInputFormatter(ApiFormatterOptions)));
            //builder.AddMvcOptions(options => options.OutputFormatters.Add(new ApiOutputFormatter(ApiFormatterOptions)));

            builder.AddMvcOptions(options =>
            {
                options.InputFormatters.Clear();
                options.InputFormatters.Add(new InputFormatter(ApiFormatterOptions));

                options.OutputFormatters.Clear();
                options.OutputFormatters.Add(new OutputFormatter(ApiFormatterOptions));

                if (ApiFormatterOptions.CommandValidationActionFilter)
                    options.Filters.Add<RequestCommandValidationActionFilter>();

                options.Filters.Add<RestFulFormatterFilter>();
            });

            return builder;
        }
    }
}
